@file:Suppress("NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate")

package com.link.play.fit.ai.ext

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContract
import androidx.activity.result.contract.ActivityResultContracts
import androidx.annotation.MainThread
import androidx.core.app.ActivityOptionsCompat
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import com.link.play.fit.ai.utils.LogX
import com.link.play.fit.ai.utils.OEM
import java.util.concurrent.atomic.AtomicInteger
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine

private val nextLocalRequestCode = AtomicInteger()

class ActivityResultLauncherObserver<T>(
    val launcher: ActivityResultLauncher<T>,
) : DefaultLifecycleObserver {
    override fun onDestroy(owner: LifecycleOwner) {
        unregister()
    }

    fun unregister() {
        launcher.unregister()
    }
}

@MainThread
inline fun Lifecycle?.removeLauncherObserver(o: ActivityResultLauncherObserver<*>?) {
    this ?: return
    o ?: return
    o.unregister()
    removeObserver(o)
}

@MainThread
inline fun <I> ActivityResultLauncher<I>.launch(
    lifecycle: Lifecycle,
    input: I,
    options: ActivityOptionsCompat? = null
): ActivityResultLauncherObserver<*> {
    val o = ActivityResultLauncherObserver(this)
    lifecycle.addObserver(o)
    launch(input, options)
    return o
}

suspend fun <I, O> ComponentActivity.launchContract(
    contract: ActivityResultContract<I, O>,
    input: I,
    options: ActivityOptionsCompat? = null
): O {
    return suspendCoroutine { c ->
        var observer: ActivityResultLauncherObserver<*>? = null
        val launcher = activityResultRegistry.register(
            "launchContract#${nextLocalRequestCode.getAndIncrement()}",
            contract
        ) {
            lifecycle.removeLauncherObserver(observer)
            c.resume(it)
        }
        observer = launcher.launch(lifecycle, input, options)
    }
}

/**
 * 系统拍照
 * @return true 表示图像成功写入 [uri]
 * @see ActivityResultContracts.TakePicture
 */
suspend fun ComponentActivity.takePicture(uri: Uri): Boolean {
    val granted = checkPermissions(Manifest.permission.CAMERA)
    if (!granted) return false
    return launchContract(ActivityResultContracts.TakePicture(), uri)
}

/**
 * 获取系统内容
 * @see ActivityResultContracts.GetContent
 */
suspend fun ComponentActivity.getContent(mimeType: String): Uri? {
    val granted = checkPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    if (!granted) return null
    return launchContract<String, Uri?>(ActivityResultContracts.GetContent(), mimeType)
}

suspend fun ComponentActivity.getContents(mimeType: String): List<Uri> {
    val granted = checkPermissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
    if (!granted) return emptyList()
    return launchContract(ActivityResultContracts.GetMultipleContents(), mimeType)
}

/**
 * 选择图片
 */
suspend fun ComponentActivity.pickImage(): Uri? {
    val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        val first = checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
        val second = checkPermissions(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
        first || second
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
    } else {
        checkPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
    }
    if (!hasPermission) return null
   // Log.e("pickImage", "pickImage")
    return getContent("image/*")
}

/** 多选图片 */
suspend fun ComponentActivity.pickImages(): List<Uri> {
    val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        val first = checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
        val second = checkPermissions(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
        first || second
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
    } else {
        checkPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
    }
    if (!hasPermission) return emptyList()
    return getContents("image/*")
}

/**
 * 检查并请求权限, 小于 6.0 (API 23) 直接拥有权限.
 *
 * *注: 请求的权限需要在 AndroidManifest.xml 中配置*
 *
 * @param permissions 需要请求的权限, 查看 [Manifest.permission]
 * @return true 表示请求的所有 [permissions] 都已允许
 */
suspend fun ComponentActivity.checkPermissions(vararg permissions: String): Boolean {
    return checkPermissionsForResult(*permissions).values.all { granted -> granted }
}

@SuppressLint("ObsoleteSdkInt")
suspend fun ComponentActivity.checkPermissionsForResult(vararg permissions: String): Map<String, Boolean> {
    //appx.debugCheck(permissions.isNotEmpty()) { "Permissions is empty" }

    if (Build.VERSION.SDK_INT < 23) {
        val map = HashMap<String, Boolean>()
        permissions.forEach {
            map[it] = true
        }
        return map
    }

    return launchContract(
        ActivityResultContracts.RequestMultiplePermissions(),
        arrayOf(*permissions)
    )
}

@SuppressLint("ObsoleteSdkInt")
fun Activity?.hasPermission(permission: String): Boolean {
    this ?: return false
    if (Build.VERSION.SDK_INT < 23) return true
    return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED
}


data class ShareParams(
    var text: String? = null,
    var uri: Uri? = null,
    var mimeType: String = MimeTypeAll,
) {
    @Suppress("SpellCheckingInspection")
    companion object {
        const val MimeTypeAll = "*/*"
        const val MimeTypeText = "text/plain"
        const val MimeTypeFile = "file/*"
        const val MimeTypeImage = "image/*"
        const val MimeTypeVideo = "video/*"
        const val MimeTypeMp4 = "video/mp4"
        const val MimeTypePdf = "application/pdf"
        const val MimeTypeZip = "application/zip"
        const val MimeTypeDocx =
            "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
        const val MimeTypeExcel =
            "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
        const val MimeTypePpt =
            "application/vnd.openxmlformats-officedocument.presentationml.presentation"

        const val ShareCancel = 0
        const val ShareSuccess = 1
        const val ShareFailed = 2
        const val ShareUnknown = 3
    }
}

/** 分享 */
suspend fun ComponentActivity.share(params: ShareParams): Boolean {
    val text = params.text
    val uri = params.uri
    if (text.isNullOrEmpty() && uri == null) {
        LogX.e("share", "set at least one of text and uri")
        return false
    }

    val shareIntent = Intent(Intent.ACTION_SEND).also {
        if (uri != null) {
            it.type = params.mimeType
            it.putExtra(Intent.EXTRA_STREAM, uri)
            it.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        } else {
            it.type = ShareParams.MimeTypeText
        }
        if (!text.isNullOrEmpty()) {
            it.putExtra(Intent.EXTRA_TEXT, text)
        }
    }

    val chooserIntent = Intent.createChooser(shareIntent, "Share")
    val result = launchContract(ActivityResultContracts.StartActivityForResult(), chooserIntent)

    return result.resultCode == Activity.RESULT_OK
}

/**
 * 系统裁剪
 * @return true 表示图像成功 [uri]
 * @see CropPhotoContract
 */
suspend fun ComponentActivity.cropPhoto(uri: Uri, outputX: Int, outputY: Int): Uri? {
    val hasPermission =
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) checkPermissions(
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.READ_EXTERNAL_STORAGE
        ) else true
    if (!hasPermission) return null
    return launchContract(CropPhotoContract(outputX, outputY), uri)
}

class CropPhotoContract(private val outputX: Int, private val outputY: Int) :
    ActivityResultContract<Uri, Uri?>() {

    var outputUri: Uri? = null
    override fun createIntent(context: Context, input: Uri): Intent {
        val intent = Intent("com.android.camera.action.CROP")
        intent.setDataAndType(input, "image/*")
        intent.putExtra("crop", "true")
        intent.putExtra("aspectX", 1)
        intent.putExtra("aspectY", 1)
        intent.putExtra("outputX", outputX)
        intent.putExtra("outputY", outputY)
        intent.putExtra("outputFormat", "JPEG")
        intent.putExtra("noFaceDetection", true)
        intent.putExtra("return-data", false)
        intent.putExtra("scaleUpIfNeeded", true)
        intent.putExtra("scale", true)
        intent.flags =
            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            //android 12及其以上不能加这个，不然进入不了裁剪
            intent.removeFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
        }
        outputUri = context.contentResolver.insertMediaImage(buildFileName(), null)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && OEM.isXiaomi) {
            intent.removeFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
            grantPermissionFix(intent, outputUri, intent.flags, context)
        }

        intent.putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
        return intent
    }

    private fun buildFileName(): String {
        val currentTime = System.currentTimeMillis()
        return "img_upload_album_$currentTime.jpg"
    }

    private fun grantPermissionFix(intent: Intent, uri: Uri?, flag: Int, mContext: Context) {
        if (mContext is Activity) {
            val resInfoList = mContext.packageManager?.queryIntentActivities(
                intent,
                PackageManager.MATCH_DEFAULT_ONLY
            ) ?: return
            for (resolveInfo in resInfoList) {
                val packageName = resolveInfo.activityInfo.packageName
                try {
                    mContext.grantUriPermission(packageName, uri, flag)
                } catch (e: Exception) {
                    continue
                }
                intent.action = null
                intent.component = ComponentName(
                    resolveInfo.activityInfo.packageName,
                    resolveInfo.activityInfo.name
                )
                break
            }
        }
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        return if (resultCode == Activity.RESULT_OK) outputUri else null
    }

}

suspend fun ComponentActivity.pickPhoto(): Uri? {
    val hasPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        val first = checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
        val second = checkPermissions(Manifest.permission.READ_MEDIA_VISUAL_USER_SELECTED)
        first || second
    } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
        checkPermissions(Manifest.permission.READ_MEDIA_IMAGES)
    } else {
        checkPermissions(Manifest.permission.READ_EXTERNAL_STORAGE)
    }
    if (!hasPermission) return null
    return launchContract(PickPhoto(), null)
}

class PickPhoto : ActivityResultContract<Uri?, Uri?>() {

    override fun createIntent(context: Context, input: Uri?): Intent {
        val openAlbumIntent = Intent(Intent.ACTION_PICK)
        openAlbumIntent.type = "image/*"
        openAlbumIntent.putExtra(Intent.EXTRA_LOCAL_ONLY, true)
        openAlbumIntent.flags =
            Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
        openAlbumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*")
        return openAlbumIntent
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        return if (resultCode == Activity.RESULT_OK) intent?.data else null
    }

}